package com.ts.gateway.filter;

import com.sun.org.apache.xpath.internal.operations.Bool;
import com.ts.common.utils.JWTUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.util.AntPathMatcher;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@RefreshScope
@Slf4j
public class TokenFilter implements GlobalFilter {
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Value("${auth.white-list}")
    private List<String> whiteList;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("whiteList:{}",whiteList);
        // 1.先取出token
        String token = exchange.getRequest().getHeaders().getFirst("token");

        // 2.获取当前请求地址，判断一下访问该接口是否需要校验token
        String url = exchange.getRequest().getURI().getPath();

        // 3、去配置文件中读取不需要token校验的路径

        // 4、比如是否校验，如果不校验直接放行

        RequestPath path = exchange.getRequest().getPath();
        // 以后路径的匹配都用这个
        boolean whiteListed = whiteList.stream().anyMatch((whiteListPath) -> antPathMatcher.match(whiteListPath, path.toString()));
        if(whiteListed){
            return chain.filter(exchange);
        }
        // 5.喀什校验token
        Boolean aBoolean = JWTUtils.checkToken(token);

        if (!aBoolean) {
            // token有误直接打回去
            Map<String, Object> r = new HashMap<>();
            r.put("code", 401);
            r.put("msg", "token有误");
            return errorInfo(exchange, "未登录");
        }

        // 6.token校验成功,需要把Token字符串的userToken信息取出来
        // 这个userInfo是UserToken对象的JSON字符串
        String userInfo = JWTUtils.getUserInfo(token);

        // 7、把userInfo放到请求头中，往下传递
        HttpHeaders headers = exchange.getRequest().getHeaders();

        // 8.创建一个新的请求头对象
        HttpHeaders newHttpHeaders = new HttpHeaders();

        // 9.把就的请求头数据添加到新的请求头对象中
        newHttpHeaders.putAll(headers);

        // 3.如果数据有中文 先编码 避免中文乱码
//        String content = URLEncoder.encode(loginUser, "UTF-8");
//        newHttpHeaders.set("loginUser", content);

        // 10.这里还可以删除请求头中的属性
        newHttpHeaders.remove("token"); // 把小程序传递过来的token给删了
        newHttpHeaders.add("userInfo", userInfo); // 后面的服务直接使用userInfo

        //11、构建一个新的请求头对象 把新的请求头对象添加进去
        ServerHttpRequest request = exchange.getRequest();
        // 创建一个新的请求对象，把新的头放到这个请求对象中
        ServerHttpRequest newRequest = request.mutate().uri(request.getURI()).build();
        newRequest = new ServerHttpRequestDecorator(newRequest) {
            @Override
            public HttpHeaders getHeaders() {
                return newHttpHeaders;
            }
        };

        // 12.放行
        return chain.filter(exchange.mutate().request(newRequest).build());
    }

    // 响应错误信息
    public static Mono<Void> errorInfo(ServerWebExchange exchange, String msg) {
        return Mono.defer(() -> {
            // 把对象转成JSON
            byte[] bytes = bytes = JSON.toJSONBytes(msg);
            // 获取响应对象
            ServerHttpResponse response = exchange.getResponse();
            // 响应响应类型
            response.getHeaders().add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
            // 设置HTTP响应码
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            DataBuffer buffer = response.bufferFactory().wrap(bytes);
            return response.writeWith(Flux.just(buffer));
        });
    }
}
